package com.woniu.aop;

import com.woniu.util.utils.HttpResult;
import com.woniu.util.utils.JWTUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
 * 操作日志切面处理类
 */
@Aspect
@Component
public class OperationLogAspect {


    @Autowired(required = false)
    OperationLogDao operationLogDao;

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 设置操作日志切入点 在注解位置切入代码
     */
    @Pointcut("@annotation(OperationLogAnnotation)")
    public void operLogPointcut() {
    }

    /**
     * 记录操作日志
     */
    @AfterReturning(returning = "result", value = "operLogPointcut()")
    public void saveOperLog(JoinPoint joinPoint, Object result) throws ParseException {
        // 获取RequestAttributes 直接获取ThreadLocal里面的值,这样就保证了每一次获取到的Request是该请求的request.
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();//RequestContextHolder既是持有上下文的Request容器
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        try {
            //将返回值转换成map集合
            HttpResult map = (HttpResult) result;
            //创建日志对象
            OperationLog operationLog = new OperationLog();
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();//MethodSignature 包含了被拦截方法的一些信息，如目标方法的返回类型，目标方法的参数列表信息
            //获取切入点所在的方法
            Method method = signature.getMethod();
            //获取操作
            OperationLogAnnotation annotation = method.getAnnotation(OperationLogAnnotation.class);
            if (annotation != null) {
                operationLog.setModel(annotation.operModul());
                operationLog.setType(annotation.operType());
                operationLog.setDescription(annotation.operDesc());
            }
            //操作时间
            operationLog.setOperationTime(Timestamp.valueOf(sdf.format(new Date())));
            //操作用户
            String jwt = request.getHeader("jwt");
            Map payLoad = JWTUtil.getPayload(jwt);
            String username = (String) payLoad.get("username");
            operationLog.setUserCode(username);
            //操作IP
            operationLog.setIp(IPUtil.getRemoteHost(request));//获取真实ip
//            operationLog.setIp(IPUtil.getLocalIp()); //获取本机ip
//            operationLog.setIp(IPUtil.getIp(request));

            //返回值信息
            operationLog.setResult(map.getMsg());
            //保存日志
            operationLogDao.insert(operationLog);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
